package yanivosher.aiproject;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Graph {
	private final List<Vertex> vertexes;
	private final List<Edge> edges;

	public Graph(List<Vertex> vertexes, List<Edge> edges) {
		this.vertexes = vertexes;
		this.edges = edges;
	}

	public List<Vertex> getVertexes() {
		return vertexes;
	}

	public List<Edge> getEdges() {
		return edges;
	}

	public Graph duplicateGraph()
	{
		List<Vertex> newVertexes = new ArrayList<Vertex>();
		for (Vertex vertex : vertexes) {
			newVertexes.add(new Vertex(vertex));
		}
		List<Edge> newEdges = new ArrayList<Edge>();
		for (Edge edge : edges) {
			newEdges.add(new Edge(edge));
		}
		return new Graph(newVertexes,newEdges);
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Graph) {
			if (!((Graph)obj).vertexes.containsAll(vertexes) && vertexes.containsAll(((Graph)obj).vertexes)) {
				return false;
			}
			if (!((Graph)obj).edges.containsAll(edges) && edges.containsAll(((Graph)obj).edges)) {
				return false;
			}
			return true;
		}
		return super.equals(obj);
	}
	
	// Get the relevant vertex from vertexes list.
	public Vertex getVertexById(String id) {
		for (Vertex vertex : vertexes) {
			if (vertex.getId().equals(id)) {
				return vertex;
			}
		}
		return null;
	}

	// Get the relevant edge from edges list.
	public Edge getEdgeBySourceDestination(Vertex src, Vertex dst) {
		
		for (Edge edge : edges) {
			if (edge.getSource().equals(src)
					&& edge.getDestination().equals(dst)) {
				return edge;
			}
		}
		//System.out.println("Edge not found: ("+src.getName() + "," + dst.getName() + ")");
		return null;
	}
	
	public Graph omittedBlockedGraph() {
		ArrayList<Edge> omittedEdges = this.unblockedEdges();
		return new Graph(this.vertexes, omittedEdges);
	}

	private ArrayList<Edge> unblockedEdges() {
		ArrayList<Edge> unblockedEdges = new ArrayList<Edge>();
		for (Edge edge : edges) {
			if (!edge.getIsBlocked()) {
				unblockedEdges.add(edge);
			}
		}
		return unblockedEdges;

	}

	
	//Return a list of all the the blocked edges vertex vacancies
	public ArrayList<Vertex> getBlockedVertexes()
	{
		ArrayList<Vertex> BlockedVertexes = new ArrayList<Vertex>();
		for (Edge edge : edges) {
			if (edge.getIsBlocked()) {
				if(!BlockedVertexes.contains(edge.getSource()))
					BlockedVertexes.add(edge.getSource());
				if(!BlockedVertexes.contains(edge.getDestination()))
					BlockedVertexes.add(edge.getDestination());
					
			}
		}
		return BlockedVertexes;
	}
	
	//Return a list of all the the vertexes with military
	public ArrayList<Vertex> getMilitaryVertexes()
	{
		ArrayList<Vertex> MilitaryVertexes = new ArrayList<Vertex>();
		for (Vertex vertex : vertexes) {
			if (vertex.getMilitary() > 0) {
				MilitaryVertexes.add(vertex);
			}
		}
		return MilitaryVertexes;
	}
	
	//Return a list of all the the vertexes with military
	public ArrayList<Vertex> getChemVertexes()
	{
		ArrayList<Vertex> MilitaryVertexes = new ArrayList<Vertex>();
		for (Vertex vertex : vertexes) {
			if (vertex.getChem() > 0) {
				MilitaryVertexes.add(vertex);
			}
		}
		return MilitaryVertexes;
	}
	
	//Return a list of all the the vertexes with military
	public void removeTerroristFromEdge(Vertex A, Vertex B)
	{
		for (Edge edge : edges) {
			if ((edge.getSource().equals(A) && edge.getDestination().equals(B)) 
					|| (edge.getSource().equals(B) && edge.getDestination().equals(A))) {
				edge.setIsBlocked(false);
			}
		}
	}
	
	public int getPathCost (LinkedList<Vertex> path){
		if (path == null || path.size() == 0)
			return 0;
		int cost = 0;
		Vertex curr = path.getFirst();
		for (Vertex vertex : path) {
			if (curr != vertex) {
				cost += getEdgeBySourceDestination(curr,vertex).getWeight();
			}
			curr = vertex;
		}
		return cost;
	}

	public ArrayList<Edge> getNeighborsEdges(Vertex source) {
		ArrayList<Edge> retList = new ArrayList<Edge>();
		for (Edge edge : edges) {
			if(edge.getSource().equals(source))
				retList.add(edge);
		}
		return retList;
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		
		sb.append("\n");
		for (Vertex vertex : this.getVertexes()) {
			sb.append(duplicateString("###", 6) + "\n");
			sb.append("Vertex : " + vertex.getId() + "\n");
			sb.append(duplicateString("###", 6) + "\n");
			sb.append("Chems  : " + vertex.getChem() + "\n");
			sb.append("Militry: " + vertex.getMilitary() + "\n");
			sb.append(duplicateString("###", 6) + "\n\n");
		}

		sb.append(duplicateString("###", 6) + "\n");

		sb.append("	#");
		for (Vertex vertexRow : this.getVertexes()) {
			sb.append(vertexRow.getId() + "       		#");
		}
		sb.append("\n");

		for (Vertex vertexRow : this.getVertexes()) {
			// Weight:
			sb.append(vertexRow.getId() + "	#");
			for (Vertex vertexCol : this.getVertexes()) {
				Edge e = this.getEdgeBySourceDestination(vertexRow, vertexCol);
				if (e != null) {
					sb.append("Weight: " + e.getWeight() + "		#");
				} else {
					sb.append("       		#");
				}
			}
			sb.append("\n");
			sb.append("	#");
			// Block :
			for (Vertex vertexCol : this.getVertexes()) {
				Edge e = this.getEdgeBySourceDestination(vertexRow, vertexCol);
				if (e != null) {
					sb.append("Block : " + e.getIsBlocked() + "		#");
				} else {
					sb.append("       		#");
				}
			}
			sb.append("\n"
					+ duplicateString("###########################",
							this.getVertexes().size()) + "\n");
		}

		return sb.toString();
	}


	private static String duplicateString(String str, int count) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < count; i++) {
			sb.append(str);
		}
		return sb.toString();
	}

	
}